!(function () {
    var _ = {
        getMin: arr => Math.min.apply(null, arr),
        getMax: arr => Math.max.apply(null, arr),
        bubbleSort: arr => {
            for (let i = 0; i < arr.length; i++) {
                for (let j = i + 1; j < arr.length; j++) {
                    if (arr[i] > arr[j]) {
                        var temp = arr[i]
                        arr[i] = arr[j]
                        arr[j] = temp
                    }
                }
            }
        },
        quickSort: arr => {
            if (arr.length <= 1) {
                return arr
            }
            var pivotIndex = Math.floor(arr.length / 2)
            var pivot = arr.splice(pivotIndex, 1)[0]
            var left = []
            var right = []
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] < pivot) {
                    left.push(arr[i])
                } else {
                    right.push(arr[i])
                }
            }
            return quickSort(left).concat([pivot], quickSort(right))
        },
        delRepeat: arr => {
            var res = []
            var n = {}
            for (var i = 0; i < arr.length; i++) {
                if (!n[arr[i]]) {
                    n[arr[i]] = true
                    res.push(arr[i])
                }
            }
            return res
        },
        countNum: arr => {
            var max = 0
            var value = []
            var obj = arr.reduce((obj, key) => {
                key in obj ? obj[key]++ : (obj[key] = 1)
                return obj
            }, {})
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    max = Math.max(max, obj[key])
                }
            }
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    if (obj[key] == max) {
                        value.push(key)
                    }
                }
            }
            return {
                max,
                value
            }
        },
        countNum2: arr => {
            var map = arr.reduce(function (m, x) {
                return m.set(x, (m.get(x) || 0) + 1)
            }, new Map())

            var res = []
            var value = [];
            for (let [k, v] of map) {
                res.push(v)
            }
            for (let [k, v] of map) {
                if (map.get(k) == _.getMax(res)) {
                    value.push(k)
                }
            }
            return {
                max: _.getMax(res),
                value: value
            }
        },
        toArray: (...args) => {
            var arr = []
            for (let i = 0; i < args.length; i++) {
                arr.push(args[i])
            }
            return arr
        },
        sortObj: (arr, key) => arr.sort((m, n) => {
            var key1 = m[key]
            var key2 = n[key]
            return key2 - key1
        }),
        where: (arr, obj) => {
            var index = []
            var keys = Object.keys(obj)
            for (let i = 0; i < arr.length; i++) {
                for (let j = 0; j < keys.length; j++) {
                    if (arr[i][keys[j]] !== obj[keys[j]]) {
                        index.push(i)
                        break
                    }
                }
            }
            var k = 0
            for (let i = 0; i < index.length; i++) {
                arr.splice(index[i] - k, 1)
                k++
            }
            return arr
        },
        sample: (arr, num) => {
            if (num == 1 || num == undefined) {
                return arr.sort(() => {
                    Math.random() - 0.5
                }).splice(0, 1)
            }
            return arr.sort(() => {
                Math.random() - 0.5
            }).splice(0, 7)
        },
        getMinDistance: (arr, obj) => {
            var result = {
                index: 0
            }
            for (var i = 0; i < arr.length; i++) {
                var x = Math.abs(arr[i].x - obj.x)
                var y = Math.abs(arr[i].y - obj.y)
                var temp = x + y
                if (i == 0) {
                    result.index = i
                    result.y = temp
                } else {
                    if (result.y > temp) {
                        result.index = i
                        result.y = temp
                    }
                }
            }
            return {
                x: arr[result.index].x,
                y: arr[result.index].y
            }
        },
        groupBy: (arr, rule) => {
            if (rule === "length") {
                var obj = arr.reduce((obj, key) => {
                    key.length in obj ? obj[key.length].push(key) : (obj[key.length] = [key])
                    return obj
                }, {})
            } else {
                var obj = arr.reduce((obj, num) => {
                    var key = rule(num);
                    key in obj ? obj[key].push(num) : (obj[key] = [num])
                    return obj
                }, {})
            }
            return obj
        },
        pluck: (arr, key) => {
            var res = []
            if (!arr[0].hasOwnProperty(key)) return;
            for (let i = 0; i < arr.length; i++) {
                res.push(arr[i][key])
            }
            return res
        },
        flatten: (arr, shallow) => {
            if (shallow) {
                var arr = arr.reduce((arr, val) => arr.concat(val), [])
            } else {
                var arr = arr.reduce((arr, val) => arr.concat(Array.isArray(val) ? _.flatten(val) : val), [])
            }
            return arr
        },
        // difference: (arr1, arr2) => {
        //     var res = [];
        //     for (var i = 0; i < arr1.length; i++) {
        //         var isEquals = false;
        //         for (var j = 0; j < arr2.length; j++) {
        //             if (arr1[i] === arr2[j]) {
        //                 isEquals = true
        //                 break
        //             }
        //         }
        //         if (!isEquals) {
        //             res.push(arr1[i])
        //         }
        //     }
        //     return res
        // },
        without: (arr, ...arg) => _.difference(arr, arg),
        intersection: (arr1, arr2) => arr1.filter(v => arr2.includes(v)),
        intersectionMore: (arr1, ...arg) => arg.length <= 1 ? arr1.filter(v => arg[0].includes(v)) : intersection(arr1.filter(v => arg[0].includes(v)), ...arg.splice(1)),
        difference: (arr1, arr2) => arr1.concat(arr2).filter(v => !arr1.includes(v) || !arr2.includes(v)),
        differenceMore: (arr1, ...arg) => _.difference(arr1, _.flatten(arg, true)),
        exclude: (arr1, ...arg) => arr1.filter(v => !arr1.includes(v) || !_.flatten(arg, true).includes(v)),
        max: (arr, rule) => {
            var num = []
            for (let i = 0; i < arr.length; i++) {
                num.push(rule(arr[i]))
            }
            var max = _.getMax(num)
            var res = arr.filter(currentValue => {
                return currentValue.age >= max
            })
            return res
        },
        shuffle: (arr) => arr.sort(() => {
            Math.random() - 0.5
        }),
        getMatrix: (arr, subArrayNum) => {
            var dataArr = new Array(Math.ceil(arr.length / subArrayNum));
            for (let i = 0; i < dataArr.length; i++) {
                dataArr[i] = new Array();
                for (let j = 0; j < i % subArrayNum; j++) {
                    dataArr[i][j] = '';
                }
            }
            for (let i = 0; i < arr.length; i++) {
                dataArr[parseInt(i / subArrayNum)][i % subArrayNum] = arr[i];
            }
            return dataArr;
        },
        keyBy: (arr, key) => arr.reduce(function (newObj, obj) {
            if (!newObj[obj[key]]) {
                newObj[obj[key]] = [];
                newObj[obj[key]].push(obj);
            } else {
                newObj[obj[key]].push(obj);
            }
            return newObj;
        }, {})
    }
    this._ = _
}.call(this))